package cc.shacocloud.mirage.bean.impl;

import cc.shacocloud.mirage.bean.ImportBeanDescriptionRegistrar;
import cc.shacocloud.mirage.bean.ImportSelector;
import cc.shacocloud.mirage.bean.bind.Import;
import cc.shacocloud.mirage.bean.meta.ImportDescription;
import cc.shacocloud.mirage.bean.meta.ImportDescriptionImpl;
import cc.shacocloud.mirage.utils.ClassUtil;
import cc.shacocloud.mirage.utils.annotation.AnnotatedElementMetadata;
import cc.shacocloud.mirage.utils.annotation.AnnotatedElementUtils;
import cc.shacocloud.mirage.utils.collection.CollUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.*;

/**
 * {@link ImportSelector} 的默认实现
 *
 * @author 思追(shaco)
 */
public class DefaultImportSelector implements ImportSelector {
    
    @Nullable
    @SuppressWarnings({"unchecked"})
    @Override
    public ImportDescription findImports(@NotNull Class<?> beanClass) {
        List<Import> imports = new LinkedList<>();
        doFindImports(beanClass, imports);
        
        if (CollUtil.isEmpty(imports)) return null;
        
        List<Class<?>> componentClass = new ArrayList<>();
        Map<ImportBeanDescriptionRegistrar, AnnotatedElementMetadata> importBeanDescriptionRegistrarMap = new HashMap<>();
        
        AnnotatedElementMetadata annotatedMetadata = AnnotatedElementUtils.getAnnotatedMetadata(beanClass);
        
        for (Import anImport : imports) {
            for (Class<?> importClass : anImport.value()) {
                
                // ImportBeanDescriptionRegistrar
                if (ClassUtil.isAssignable(ImportBeanDescriptionRegistrar.class, importClass)) {
                    ImportBeanDescriptionRegistrar importBeanDescriptionRegistrar = createImportBeanDescriptionRegistrar((Class<? extends ImportBeanDescriptionRegistrar>) importClass);
                    importBeanDescriptionRegistrarMap.put(importBeanDescriptionRegistrar, annotatedMetadata);
                }
                // 普通的组件类
                else {
                    componentClass.add(importClass);
                }
                
            }
        }
        
        return new ImportDescriptionImpl(componentClass, importBeanDescriptionRegistrarMap);
    }
    
    /**
     * 使用无参构造函数创建 {@link ImportBeanDescriptionRegistrar} 实例
     *
     * @return {@link ImportBeanDescriptionRegistrar}
     */
    protected ImportBeanDescriptionRegistrar createImportBeanDescriptionRegistrar(Class<? extends ImportBeanDescriptionRegistrar> clazz) {
        try {
            return ClassUtil.instantiateClass(clazz);
        } catch (Exception e) {
            throw new IllegalStateException(String.format("通过无参构造函数实例化 ImportBeanDescriptionRegistrar 的实现类 %s 发生例外！", clazz), e);
        }
    }
    
    /**
     * 寻找 {@link Import} 以及其声明的注解元素
     */
    protected void doFindImports(@NotNull AnnotatedElement annotatedElement,
                                 @NotNull List<Import> imports) {
        for (Annotation annotation : annotatedElement.getAnnotations()) {
            Class<? extends Annotation> annotationType = annotation.annotationType();
            
            if (Import.class.equals(annotationType)) {
                imports.add((Import) annotation);
            }
            
            if (AnnotatedElementUtils.isNotMateAnnotation(annotationType)) {
                doFindImports(annotationType, imports);
            }
        }
    }
    
}
